/**
 * Created by Weizehua on 2017/1/19.
 */
import {Constructor} from "ts.di";
import {logger} from "../../Core/Logger/Logger";

export class Metadata {
    static paramTypes(func: Function) {
        if (!func[Metadata.paramTypesSymbol]) {
            throw new Error(`Before getting ${func.name} 's param-types, use Metadata.register...() function to register it.`);
        }
        return func[Metadata.paramTypesSymbol];
    }

    static returnType(func: Function) {
        if (!func[Metadata.returnTypeSymbol]) {
            throw new Error(`Before getting ${func.name} 's return type, use Metadata.register...() function to register it.`);
        }
        return func[Metadata.returnTypeSymbol];
    }

    static ctor<T>(func: Function): Constructor<T> {
        if (!func[Metadata.ctorTypeSymbol]) {
            throw new Error(`Before getting ${func.name} 's constructor, use Metadata.register...() function to register it.`);
        }
        return func[Metadata.ctorTypeSymbol];
    }

    // static registerTypesForAllFuncInClass<T>(ctor: Constructor<T>) {
    //     if (ctor[Metadata.isClassRegistered]) {
    //         return;
    //     }
    //     Metadata.registerTypesForAllPropertyInTarget(ctor, ctor);
    //     Metadata.registerTypesForAllPropertyInTarget(ctor.prototype, ctor);
    //     ctor[Metadata.paramTypesSymbol] = Reflect.getMetadata("design:paramtypes", ctor) || [];
    //     ctor[Metadata.returnTypeSymbol] = Reflect.getMetadata("design:returntype", ctor);
    //     ctor[Metadata.ctorTypeSymbol] = ctor;
    //     ctor[Metadata.isClassRegistered] = true;
    // }

    static registerTypesForClassFunc<T>(target: Object, propertyKey: string|symbol, ctor: Constructor<T>) {
        let func = target[propertyKey];
        if (typeof func !== 'function' || func[Metadata.isFunctionRegistered]) {
            return;
        }
        func[Metadata.paramTypesSymbol] = Reflect.getMetadata("design:paramtypes", target, propertyKey) || [];
        func[Metadata.returnTypeSymbol] = Reflect.getMetadata("design:returntype", target, propertyKey);
        func[Metadata.ctorTypeSymbol] = ctor;
        func[Metadata.isFunctionRegistered] = true;
        logger.debug(`Metadata register for : ${ctor.name}.${target[propertyKey].name}`);
    }

    // static copyRegisteredTypes(src: Object, dst: Object) {
    //     dst[Metadata.paramTypesSymbol] = src[Metadata.paramTypesSymbol];
    //     dst[Metadata.returnTypeSymbol] = src[Metadata.returnTypeSymbol];
    //     dst[Metadata.ctorTypeSymbol] = src[Metadata.ctorTypeSymbol];
    // }

    // static copyUnRegisteredTypes(srcTarget:Object, srcPropertyKey: string|symbol, dst: Object) {
    //     Metadata.registerTypesForClassFunc(srcTarget, srcPropertyKey);
    //     Metadata.copyRegisteredTypes(srcTarget[srcPropertyKey], dst);
    // }

    // private static registerTypesForAllPropertyInTarget<T>(target: Object, ctor: Constructor<T>) {
    //     if (target[Metadata.isTargetRegistered]) {
    //         return;
    //     }
    //     for (let i in target) {
    //         if (target.hasOwnProperty(i)) {
    //             Metadata.registerTypesForClassFunc(target, i, ctor);
    //         }
    //     }
    //     target[Metadata.isTargetRegistered] = true;
    // }

    private static paramTypesSymbol = Symbol('Metadata.paramTypesSymbol');
    private static returnTypeSymbol = Symbol('Metadata.returnTypeSymbol');
    private static ctorTypeSymbol = Symbol('Metadata.ctorTypeSymbol');
    private static isFunctionRegistered = Symbol("Metadata.isFunctionRegistered");
    private static isTargetRegistered = Symbol("Metadata.isTargetRegistered");
    // private static isClassRegistered = Symbol("Metadata.isClassRegistered");
}

